#include "protosrvmanager.h"

std::auto_ptr<ProtoSrvManager>   ProtoSrvManager::_mgr;

ProtoSrvManager::ProtoSrvManager()
{
    _srv_map.clear();
}

ProtoSrvManager::~ProtoSrvManager()
{
    std::map<std::string,ProtoSrv *>::iterator it;
    for(it = _srv_map.begin();it != _srv_map.end();it++){
        delete it->second;
    }
}

std::auto_ptr<ProtoSrvManager>& ProtoSrvManager::getInstance()
{
    if(_mgr.get() == 0){
        _mgr.reset(new ProtoSrvManager());
    }
    return _mgr;
}

void ProtoSrvManager::registerProtoSrv(ProtoSrv* srv)
{
    if(srv){
	QString name;
        name.setNum(srv->getProtocolType());

	_srv_map[name.toStdString()] = srv;

        ACE_DEBUG((LM_DEBUG,"Register Service(%d,%s)\n",srv->getProtocolType(),typeid(*srv).name()));
    }
}

ProtoSrv* ProtoSrvManager::getProtoSrv(qint32 proType)
{
    QString name;
    name.setNum(proType);
    if(_srv_map.count(name.toStdString()))
	return _srv_map[name.toStdString()];

    return 0;
}

bool ProtoSrvManager::encode(ACE_OutputCDR &cdr,ProtoSrv* srv)
{
    bool res = false;
    if(srv == 0)
	return res;

    ACE_OutputCDR msgCDR;
    if(srv->encode(msgCDR)){
	cdr << ACE_CDR::UShort(ACE_CDR_BYTE_ORDER); //byte order
        cdr << ACE_CDR::UShort(srv->getProtocolType());         //protocol type
        cdr << ACE_CDR::ULong(msgCDR.total_length());        //payload length

	res = srv->encode(cdr);
    }

    return res;
}

ProtoSrv* ProtoSrvManager::decode(ACE_SOCK_Stream &stream)
{
    std::auto_ptr<ACE_Message_Block> msgBlock(new ACE_Message_Block(10 * ACE_DEFAULT_CDR_BUFSIZE));
    ACE_CDR::mb_align(msgBlock.get());

    ssize_t header_len = sizeof(ACE_CDR::UShort) + sizeof(ACE_CDR::UShort) + sizeof(ACE_CDR::ULong);
    if(stream.recv_n(msgBlock->wr_ptr(),header_len) == header_len){
        //ACE_DEBUG((LM_DEBUG,"Got Header:%d\n",header_len));

        msgBlock->wr_ptr(header_len);

        ACE_InputCDR cdr(msgBlock.get());

        ACE_CDR::Boolean byteOrder;
        cdr >> ACE_InputCDR::to_boolean(byteOrder);
        cdr.reset_byte_order(byteOrder);

        ACE_CDR::UShort protoType;
        cdr >> protoType;
        //ACE_DEBUG((LM_DEBUG,"Got Proto:%d\n",protoType));

        ACE_CDR::ULong length;
        cdr >> length;
        //ACE_DEBUG((LM_DEBUG,"Got Msg Len:%d\n",length));

        std::auto_ptr<ACE_Message_Block> message(new ACE_Message_Block(length + ACE_CDR::MAX_ALIGNMENT));
        ACE_CDR::mb_align(message.get());

	ssize_t recv_len = stream.recv_n(message->wr_ptr(),length);
	if(recv_len == (ssize_t)length){
            message->wr_ptr(length);

            //ACE_DEBUG((LM_DEBUG,"Got Msg:%d\n",length));

            ACE_InputCDR icdr(message.get());
            ProtoSrv* service = ProtoSrvManager::getInstance()->getProtoSrv(protoType);
            if(service){
                //ACE_DEBUG((LM_DEBUG,"Find Proto Type:%d\n",protoType));
                return service->decode(icdr);
            }
            else
                ACE_DEBUG((LM_DEBUG,"Got Unknown Service(%d)\n",protoType));
        }
	//ACE_DEBUG((LM_DEBUG,"Got Part Msg:%d\n",recv_len));
    }

    return 0;
}
